package com.rk.kbk.service;

import cn.jiguang.common.resp.APIConnectionException;
import cn.jiguang.common.resp.APIRequestException;
import cn.jpush.api.JPushClient;
import cn.jpush.api.push.PushResult;
import cn.jpush.api.push.model.Message;
import cn.jpush.api.push.model.Options;
import cn.jpush.api.push.model.Platform;
import cn.jpush.api.push.model.PushPayload;
import cn.jpush.api.push.model.audience.Audience;
import cn.jpush.api.push.model.notification.IosNotification;
import cn.jpush.api.push.model.notification.Notification;
import com.alibaba.fastjson.JSONObject;
import com.rk.kbk.common.MapUtils;
import com.rk.kbk.common.PubLib;
import com.rk.kbk.dao.AddressDao;
import com.rk.kbk.dao.OrderDao;
import com.rk.kbk.dao.SendRatesDao;
import com.rk.kbk.dao.UserDao;
import com.rk.kbk.model.Address;
import com.rk.kbk.model.Order;
import com.rk.kbk.model.SendRates;
import com.rk.kbk.model.User;
import org.apache.log4j.Logger;
import org.hibernate.SQLQuery;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @OrderService
 * @订单Service
 * @version : Ver 1.0
 */
@Service
@Transactional
public class OrderService {
    private Logger log = Logger.getLogger(this.getClass());
    @Autowired
    private OrderDao orderDao;
    @Autowired
    private AddressDao addressDao;
    @Autowired
    private UserDao userDao;
    @Autowired
    private SendRatesDao sendRatesDao;
    @PersistenceContext
    private EntityManager entityManager;

    private final static String appKey = "24ff2702b1e148bed46bfd38";

    private final static String masterSecret = "b3d293035d8d15aaa11d2e2e";

    private static JPushClient jPushClient = new JPushClient(masterSecret,appKey);

    private   ScheduledExecutorService service;
    private  static final  Lock lock  =new ReentrantLock();
    /**
     * 获取配送费和配送限制时间
     */
    public Map findSendMoney(String lat, String lng, Long shopId){
       Map map=new HashMap();
       Address address= addressDao.findOne(userDao.findOne(shopId).getAddress());
       String areaCode =address.getAreaCode();
       List<SendRates> sendRateList = sendRatesDao.findByAreaCodeOrderByAreaLengthAsc(areaCode);
       String latng=address.getLng()+","+address.getLat();
       String latng1= lng+","+lat;
       List<String> distanceList= MapUtils.manyDistance(latng1,latng);
       Double  distance=Double.valueOf(distanceList.get(0))/1000;
       Double sendMoney = null;Integer limitTime=null;
       if (sendRateList.isEmpty()) {
           map.put("sendMoney","-1");
           map.put("limitTime","-1");
       }
       int i = 0, y = sendRateList.size();
       for (; i < y; i++) {
           SendRates sendRates = sendRateList.get(i);
           if (Double.valueOf(distance).compareTo(Double.valueOf(sendRates.getAreaLength())) <= 0) {
               sendMoney = sendRates.getSendFee();
               limitTime=sendRates.getDeliverTime();
               break;
           }
           if (i == y - 1) {
               sendMoney = sendRates.getSendFee();
               limitTime=sendRates.getDeliverTime();
           }
       }
       if(sendMoney==null){
           map.put("sendMoney","-2");
           map.put("limitTime","-2");
       }else {
           map.put("sendMoney",sendMoney);
           map.put("limitTime",limitTime);
       }
       return map;
   }
    /**
     * 获取商家准时出货率
     */
   public String findOntimeDeliveryRate(User shop){
       Double onTimeDeliveryRate=1.00;
       List<Order> orderByShopList=orderDao.findByShop(shop);
       int takeOrderNum=0, n=0,b=orderByShopList.size(),totalOrderNum=0;
       for(;n<b;n++){
           Order order2=orderByShopList.get(n);
           if(order2.getOrderStatus()!=0){
               ++totalOrderNum;
               if(order2.getIsTakeExcept()==0){
                   ++takeOrderNum;
               }
           }
       }
       if(totalOrderNum!=0){
           onTimeDeliveryRate=new BigDecimal(takeOrderNum).divide(new BigDecimal(totalOrderNum),4,BigDecimal.ROUND_HALF_UP).doubleValue();//获得准时出货率
       }
       DecimalFormat df = new DecimalFormat("0.00%");
       if(onTimeDeliveryRate==1.00 || onTimeDeliveryRate==1.0000){
           return  "100%";
       }else {
           return String.valueOf(df.format(onTimeDeliveryRate));
       }

   }
/**
 *
 * 获取我 到 取货地点 到送货地点 距离
 * 例如 3.4-5.6 3.4为我到取货地点距离 5.6为取货地点到送货地点距离
 */

public  String findDistance(Long orderId){
    Order order=orderDao.findOne(orderId);
    Address addressUser=order.getAddressUser();
    Address addressShop=order.getAddressShop();
    User ride=order.getRide();
    Address addressRide=addressDao.findOne(ride.getAddress());
    String latngFirst=addressRide.getLng()+","+addressRide.getLat();
    String latngSecond=addressUser.getLng()+","+addressUser.getLat();
    String latngThird=addressShop.getLng()+","+addressShop.getLat();
    String str=latngFirst+"|"+latngSecond;
    List<String> lengList= MapUtils.manyDistance(str,latngThird);
    String str2="",str3="";
    for(int i=0,y=lengList.size();i<y;i++){
        BigDecimal bigDecimal=new BigDecimal(lengList.get(i)).divide(new BigDecimal(1000),2,BigDecimal.ROUND_HALF_UP);
        str2+= bigDecimal+"-";
    }
    if(!"".equals(str2)){
        str3=str2.substring(0,str2.length()-1);
    }
    return str3;
}






    /**
     * 处理日订单序号
     */
    public Integer findDayOrderIndex(User user){
        List<Order> orderList = orderDao.findByShopOrderByGmtDatetimeDescDayOrderIndexDesc(user);
        int dayOrderIndex = -1;
        if (orderList.size()==1) {
            dayOrderIndex = 1;
        } else {
            for(int i=0,y=orderList.size();i<y;i++){
                Order order=null;
                if(i==y-1){
                    order=orderList.get(i);
                    dayOrderIndex = order.getDayOrderIndex() + 1;
                    break;
                }else {
                    order=orderList.get(i+1);
                    if(order.getOrderStatus()==0){
                        continue;
                    }
                }
                Date gmtDateTime = order.getGmtDatetime();
                DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                String gmtDateTimeStr = gmtDateTime.toString().substring(0, 10);
                String currentDateTimeStr = dateFormat.format(new Date());
                //如果上一个订单产生日期不是今天
                if (java.sql.Date.valueOf(currentDateTimeStr).after(java.sql.Date.valueOf(gmtDateTimeStr))) {
                    dayOrderIndex = 1;
                    break;
                    //如果上一个订单产生日期是今天 则查看上一订单序号
                } else if (java.sql.Date.valueOf(currentDateTimeStr).equals(java.sql.Date.valueOf(gmtDateTimeStr))) {
                    dayOrderIndex = order.getDayOrderIndex() + 1;
                    break;
                }
            }
        }
        return  dayOrderIndex;
    }
    /**
     * 新建订单消息推送
     * fullTime 1代表全职2代表兼职
     */
     public List  findAllAlaias(Order order,Integer fullTime){
         Address shop=order.getAddressShop();
         String areaCode=shop.getAreaCode();
      //   List<Address> addressList=addressDao.findByTypeAndStatusAndAreaCode(4,1,shop.getAreaCode());
//         String sql= "select a.alias, a.phone,b.lng, b.lat from user a,address b where a.address = b.id and b.type = 4 " +
//                 " and b.status = 1 and a.full_time="+fullTime +" and b.area_code="+areaCode;
         String sql="SELECT a.alias,a.id,b.lng,b.lat ,b.area_code,a.real_name ,b.gmt_datetime FROM user a," +
                 "(SELECT a.ride_id, a.id,a.lng,a.lat ,a.area_code,a.gmt_datetime FROM dynamic_place a " +
                 "INNER JOIN (SELECT MAX(id) id,ride_id FROM dynamic_place GROUP BY ride_id)b ON a.ride_id=b.ride_id AND a.id=b.id ORDER BY a.ride_id) b " +
                 "WHERE a.id=b.ride_id and a.full_time="+fullTime +" and b.area_code="+areaCode;
         Query query = entityManager.createNativeQuery(sql);
         entityManager.close();
         query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
         List<Map> mapList = new ArrayList<>();
         query.getResultList().forEach(n -> mapList.add(PubLib.copyObject(PubLib.convert(n), Map.class)));
         String origins="";
         int i=0,y=mapList.size(),index=0;
         String alias[]=new String[y];
         for(;i<y;i++){
             Map map=mapList.get(i);
             if("".equals(String.valueOf(map.get("lng"))) || "".equals(String.valueOf(map.get("lat")))){
                 continue;
             }
             origins+=String.valueOf(map.get("lng"))+","+String.valueOf(map.get("lat"))+"|";
             alias[index]=String.valueOf(map.get("alias"));
             index++;
         }
         List<String> aliasList=new ArrayList<>();
         if(!"".equals(origins)){
             origins=origins.substring(0,origins.length()-1);
         }else {
             return aliasList;
         }
         String destination=shop.getLng()+","+shop.getLat();
        List<String> distanceList= MapUtils.manyDistance(origins,destination);
         for(int m=0,n=distanceList.size();m<n;m++){
             String distance=distanceList.get(m);
          if(Double.valueOf(distance).compareTo(Double.valueOf(5000))<0){//小于5公里
              aliasList.add(alias[m]);
          }
         }
         return aliasList;
     }

    /**
     * 定时任务
     */
    public  void   taskPush(Long orderId) {
        Order order = orderDao.findOne(orderId);
        Runnable runnable = new Runnable() {
            public void run() {
                // task to run goes here
                if (order.getOrderStatus() == 1) {
                    String msg_content = "有新的订单产生，请留意！";
                    JSONObject jsonObject2 = new JSONObject();
                    jsonObject2.put("type", 10);
                    jsonObject2.put("id", order.getId());
                    List aliasList = findAllAlaias(order, 2);
                    if(!aliasList.isEmpty()){
                        int n = OrderService.sendToAliasId(aliasList, "新订单通知", "新订单", msg_content, jsonObject2.toString());
                        log.debug("定时任务。。推送给兼职骑手，推送状态n=" + n);
                    }
                    if (!service.isShutdown()) {
                        service.shutdown();
                    }
                }
            }
        };
        service = Executors
                .newSingleThreadScheduledExecutor();
        // 第二个参数为首次执行的延时时间，第三个参数为定时执行的间隔时间
        service.scheduleAtFixedRate(runnable, 30, 1, TimeUnit.SECONDS);


    }


    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            public void run() {
              System.out.print(1);
            }
        };
        ScheduledExecutorService    service2 = Executors
                .newSingleThreadScheduledExecutor();
        // 第二个参数为首次执行的延时时间，第三个参数为定时执行的间隔时间
        service2.scheduleAtFixedRate(runnable, 5, 1, TimeUnit.SECONDS);


    }




    /**
     * 推送给别名参数的用户
     * @param aliasList 设备标识
     * @param notification_title 通知内容标题
     * @param msg_title 消息内容标题
     * @param msg_content 消息内容
     * @param extrasparam 扩展字段
     * @return 0推送失败，1推送成功
     */
    public static int sendToAliasId(List<String> aliasList, String notification_title, String msg_title, String msg_content, String extrasparam) {
        int result = 0;
        try {
            PushPayload pushPayload= OrderService.buildPushObject_all_alias_alertWithTitle(aliasList,notification_title,msg_title,msg_content,extrasparam);
            System.out.println(pushPayload);
            PushResult pushResult=jPushClient.sendPush(pushPayload);
            System.out.println(pushResult);
            if(pushResult.getResponseCode()==200){
                result=1;
            }
        } catch (APIConnectionException e) {
            e.printStackTrace();

        } catch (APIRequestException e) {
            e.printStackTrace();
        }

        return result;
    }


    private static PushPayload buildPushObject_all_alias_alertWithTitle(List<String> aliasList,String notification_title, String msg_title, String msg_content, String extrasparam) {

        System.out.println("----------buildPushObject_all_all_alert");
        //创建一个IosAlert对象，可指定APNs的alert、title等字段
        //IosAlert iosAlert =  IosAlert.newBuilder().setTitleAndBody("title", "alert body").build();

        return PushPayload.newBuilder()
                //指定要推送的平台，all代表当前应用配置了的所有平台，也可以传android等具体平台
                .setPlatform(Platform.all())
                //指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id
                .setAudience(Audience.alias(aliasList))
                //jpush的通知，android的由jpush直接下发，iOS的由apns服务器下发，Winphone的由mpns下发
                .setNotification(Notification.newBuilder()
                        //指定当前推送的android通知
                        /*.addPlatformNotification(AndroidNotification.newBuilder()

                                .setAlert(notification_title)
                                .setTitle(notification_title)
                                //此字段为透传字段，不会显示在通知栏。用户可以通过此字段来做一些定制需求，如特定的key传要指定跳转的页面（value）
                                .addExtra("KEY",extrasparam)

                                .build())*/
                        //指定当前推送的iOS通知
                        .addPlatformNotification(IosNotification.newBuilder()
                                //传一个IosAlert对象，指定apns title、title、subtitle等
                                .setAlert(notification_title)
                                //直接传alert
                                //此项是指定此推送的badge自动加1
                                .incrBadge(1)
                                //此字段的值default表示系统默认声音；传sound.caf表示此推送以项目里面打包的sound.caf声音来提醒，
                                // 如果系统没有此音频则以系统默认声音提醒；此字段如果传空字符串，iOS9及以上的系统是无声音提醒，以下的系统是默认声音
                                .setSound("sound.caf")
                                //此字段为透传字段，不会显示在通知栏。用户可以通过此字段来做一些定制需求，如特定的key传要指定跳转的页面（value）
                                .addExtra("KEY",extrasparam)
                                //此项说明此推送是一个background推送，想了解background看：http://docs.jpush.io/client/ios_tutorials/#ios-7-background-remote-notification
                                //取消此注释，消息推送时ios将无法在锁屏情况接收
                                // .setContentAvailable(true)

                                .build())


                        .build())
                //Platform指定了哪些平台就会像指定平台中符合推送条件的设备进行推送。 jpush的自定义消息，
                // sdk默认不做任何处理，不会有通知提示。建议看文档http://docs.jpush.io/guideline/faq/的
                // [通知与自定义消息有什么区别？]了解通知和自定义消息的区别
                .setMessage(Message.newBuilder()

                        .setMsgContent(msg_content)

                        .setTitle(msg_title)

                        .addExtra("KEY",extrasparam)

                        .build())

                .setOptions(Options.newBuilder()
                        //此字段的值是用来指定本推送要推送的apns环境，false表示开发，true表示生产；对android和自定义消息无意义
                        .setApnsProduction(false)
                        //此字段是给开发者自己给推送编号，方便推送者分辨推送记录
                        .setSendno(1)
                        //此字段的值是用来指定本推送的离线保存时长，如果不传此字段则默认保存一天，最多指定保留十天；
                        .setTimeToLive(86400)

                        .build())

                .build();

    }


}
